﻿using AspectCore.DynamicProxy;
using AspectCore.DynamicProxy.Parameters;
using Cyss.Core.Cache;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;

namespace Cyss.Core.Attributes
{
    /// <summary>
    /// aop 方法结果缓存
    /// </summary>
    [AttributeUsage(AttributeTargets.Method)]
    public class CacheAttribute : AbstractInterceptorAttribute
    {
        /// <summary>
        /// 锁key
        /// </summary>
        public string Key { set; get; }

        /// <summary>
        /// 过期时间(分钟)
        /// </summary>
        public int CacheTime { set; get; } = 60*25;

        /// <summary>
        /// 是否是异步方法
        /// </summary>
        private bool? IsAsync { set; get; }


        /// <summary>
        /// 
        /// </summary>
        private IStaticCacheManager _staticCacheManager { set; get; }

        public override async Task Invoke(AspectContext context, AspectDelegate next)
        {

            if (_staticCacheManager==null)
            {
                _staticCacheManager=IOCEngine.Resolve<IStaticCacheManager>();
            }
            if (string.IsNullOrWhiteSpace(this.Key))
            {
                this.Key =context.ServiceMethod.DeclaringType.Name+"-"+context.ServiceMethod.Name;
            }
            if (!IsAsync.HasValue)
            {
                if (context.ServiceMethod.GetCustomAttributes(false).Any(x => x.GetType()== typeof(AsyncStateMachineAttribute)))
                {
                    IsAsync=true;
                }
                else
                {
                    IsAsync =false;
                }
            }
            string key = GetCahceKey(context.Parameters);
            var returnType = context.GetReturnParameter().Type;
            if (IsAsync.Value)
            {
                returnType=returnType.GenericTypeArguments.FirstOrDefault();
            }
            if (_staticCacheManager.IsSet(key))
            {
                var value = _staticCacheManager.Get<string>(key);
                var objValue = JsonHelper.DeserializeObject(value, returnType);
                if (IsAsync.Value)
                {
                    context.ReturnValue=typeof(Task).GetMethod(nameof(Task.FromResult)).MakeGenericMethod(returnType).Invoke(null, new object[] { objValue });
                }
                else
                {
                    context.ReturnValue=objValue;
                }
            }
            else
            {
                await next(context);
                if (IsAsync.Value)
                {
                    _staticCacheManager.Set(key, context.ReturnValue.GetPropertieValue("Result").ToSerializeObject(), this.CacheTime);
                }
                else
                {
                    _staticCacheManager.Set(key, context.ReturnValue.ToSerializeObject(), this.CacheTime);
                }
            }
        }

        private string GetCahceKey(object[] pars)
        {
            return "CacheAttribute:"+this.Key+"-par:"+pars.FormatParameters();
        }
    }
}
